package com.jews.framework.easyexcel.utils;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.jews.framework.easyexcel.exception.EasyExcelException;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.T;

import java.io.InputStream;
import java.net.URL;
import java.util.*;
import java.util.stream.Collectors;

/**
 * excel导出工具包
 *
 * @author JewsChen
 * @title: EasyExcelUtils
 * @date 2023/2/2 17:57
 */
@Slf4j
public class EasyExcelUtils {

    private EasyExcelUtils() {
    }

    /**
     * 读取Excel
     *
     * @param url           Excel链接
     * @param clazz         Excel对象头
     * @param sheetNo       第几个sheet
     * @param sheetName     sheet名称
     * @param headRowNumber 第几行开始读
     * @param listener      分析监听器
     */
    public static void readUrl(String url, Class<T> clazz, int sheetNo, String sheetName, int headRowNumber, AnalysisEventListener listener) {
        try (InputStream is = new URL(url).openStream()) {
            readInputStream(is, clazz, sheetNo, sheetName, headRowNumber, listener);
        } catch (Exception e) {
            log.error("EasyExcelUtils readUrl fail", e);
            throw new EasyExcelException("读取文件失败", e);
        }
    }

    /**
     * 写入Excel文件,适用于导入固定列。成功记得删除临时文件
     *
     * @param pathName  文件名
     * @param sheetNo   第几个sheet
     * @param sheetName sheet名称
     * @param clazz     Excel对象头
     * @param dataList  数据集合
     * @param isFinish  isFinish
     */
    public static <T> void writeBeanToExcel(String pathName, int sheetNo, String sheetName, Class<T> clazz, List<T> dataList, boolean isFinish) {
        write(pathName, sheetNo, sheetName, clazz, dataList, isFinish);
    }


    /**
     * 写入成功记得删除临时文件
     *
     * @param pathName   文件名
     * @param sheetNo    第几个sheet
     * @param sheetName  sheet名称
     * @param headerMap 表头名集合
     * @param datas      数据集合
     * @param isFinish   isFinish
     */
    public static void writeMapToExcel(String pathName, int sheetNo, String sheetName, Map<String, String> headerMap, List<Map<String, Object>> datas, boolean isFinish) {
        List<List<String>> singletonHeaderList = new ArrayList<>(headerMap.values()).stream()
                .map(Collections::singletonList).
                collect(Collectors.toList());

        List<List<Object>> singletonDataList = new ArrayList<>();
        for (Map<String, Object> data : datas) {
            List<Object> values = new ArrayList<>();
            for (Map.Entry entry : headerMap.entrySet()) {
                values.add(data.get(entry.getKey()));
            }
            singletonDataList.add(values);
        }
        write(pathName, sheetNo, sheetName, singletonHeaderList, singletonDataList, isFinish);
    }

    /**
     * @param is            文件输入流
     * @param clazz         Excel对象头
     * @param sheetNo       第几个sheet
     * @param sheetName     sheet名称
     * @param headRowNumber 第几行开始读
     * @param listener      分析监听器
     */
    private static void readInputStream(InputStream is, Class<T> clazz, int sheetNo, String sheetName, int headRowNumber, AnalysisEventListener listener) {
        if (sheetName != null) {
            EasyExcel.read(is, clazz, listener).sheet(sheetName).headRowNumber(headRowNumber).doRead();
        } else {
            EasyExcel.read(is, clazz, listener).sheet(sheetNo).headRowNumber(headRowNumber).doRead();
        }
    }

    /**
     * 写入成功记得删除临时文件
     *
     * @param pathName  文件名
     * @param sheetNo   第几个sheet
     * @param sheetName sheet名称
     * @param clazz     Excel对象头
     * @param data      data
     * @param isFinish  isFinish
     */
    private static <T> void write(String pathName, int sheetNo, String sheetName, Class<T> clazz, List<T> data, boolean isFinish) {
        WriteSheet ws = EasyExcel.writerSheet(sheetNo, sheetName)
                .head(clazz)
                .build();

        ExcelWriter ew = EasyExcel.write(pathName)
                .registerWriteHandler(EasyExcelStyleStrategy.getExportDefaultStyle())
                .build();

        ew.write(Optional.ofNullable(data).orElse(new ArrayList<>()), ws);

        if (isFinish) {
            ew.finish();
        }
    }


    /**
     * 写入成功记得删除临时文件
     *
     * @param pathName  文件名
     * @param sheetNo   第几个sheet
     * @param sheetName sheet名称
     * @param header    表头名集合
     * @param data      data
     * @param isFinish  isFinish
     */
    private static <T> void write(String pathName, int sheetNo, String sheetName, List<List<String>> header, List<T> data, boolean isFinish) {
        WriteSheet ws = EasyExcel.writerSheet(sheetNo, sheetName)
                .head(header)
                .build();

        ExcelWriter ew = EasyExcel.write(pathName)
                .registerWriteHandler(EasyExcelStyleStrategy.getExportDefaultStyle())
                .build();

        ew.write(Optional.ofNullable(data).orElse(new ArrayList<>()), ws);

        if (isFinish) {
            ew.finish();
        }
    }

}
